#include <all_wlib.h>
#pragma hdrstop
//#pragma package(smart_init)
#pragma resource "*.dfm"
#pragma link "BkList"

#include "ghed_int.h"
#include "ghe_FontEdit.h"

LOCALSTRUCT( CharInfo )
  DWORD off;
  int   nLen;
  int   nPair;
  int   nChars;
  CONSTSTR Name;
};
static CharInfo KnownChars[] = {
  { 0x38000, 1, 6, 256, "0x38000 Eng small 6x8x256" },
  { 0x38600, 2, 8, 64,  "0x38600 Eng big 8x16x64" }
};

//---------------------------------------------------------------------------
//  HCustomCharImage
//---------------------------------------------------------------------------
__fastcall HCharImage::HCharImage( TComponent *Owner ) : HCustomCharImage(Owner) {}

__fastcall HCustomCharImage::HCustomCharImage( TComponent *Owner )
   : TGraphicControl(Owner)
  {
     FItemIndex   = -1;
     FFontBitmap  = NULL;
     FDotSize     = 10;
}

void __fastcall HCustomCharImage::idChange( TObject *Sender ) { Change(); }
void __fastcall HCustomCharImage::Change( void )              { ItemIndex = ItemIndex; }
void __fastcall HCustomCharImage::idItemChange( TObject *Sender, int idx ) { if ( idx == ItemIndex ) Change(); }

DECL_PROP_SET( HCustomCharImage, int,  DotSize ) { HPropModify( FDotSize, val, &Change ); }

DECL_PROP_SET( HCustomCharImage, int, ItemIndex )
  {
     FItemIndex = val;
     if ( !FontBitmap ||
          !CharDump.Resize( FontBitmap->CharWidthB*FontBitmap->CharHeight) ||
          !FontBitmap->GetCharDump( (LPBYTE)CharDump.Ptr(), ItemIndex ) )
       CharDump.Free();
     Invalidate();
}

DECL_PROP_SET( HCustomCharImage, PHCustomFontBitmap, FontBitmap )
  {
     if ( FFontBitmap == val ) return;

     if ( FFontBitmap ) {
       FFontBitmap->Changes.Delete( idChange );
       FFontBitmap->ItemChanges.Delete( idItemChange );
     }

     FFontBitmap = val;

     if ( FFontBitmap ) {
       FFontBitmap->Changes.Add( idChange );
       FFontBitmap->ItemChanges.Add( idItemChange );
     }

     Change();
}

void __fastcall HCustomCharImage::Notification( TComponent* p, TOperation op )
  {
     if ( p == FFontBitmap && op == opRemove )
       FontBitmap = NULL;

     TGraphicControl::Notification( p, op );
}

bool __fastcall HCustomCharImage::GetDot( int x, int y )
  {
     if ( CharDump.Sizeof() || !FontBitmap )
       return false;
     LPBYTE b = (LPBYTE)CharDump.Ptr();

 return IS_FLAG( b[ y*FontBitmap->CharWidthB + x/8 ], 1<<(x%8) );
}

void __fastcall HCustomCharImage::SetDot( int x, int y, bool dot )
  {
     if ( !CharDump.Sizeof() ||
          !FontBitmap )
       return;
     LPBYTE b = (LPBYTE)CharDump.Ptr();
     BYTE   v = 1<<(x%8);

     b += y*FontBitmap->CharWidthB + x/8;

     if ( dot )
       SET_FLAG( *b, v );
      else
       CLR_FLAG( *b, v );

     FontBitmap->SetCharDump( (LPBYTE)CharDump.Ptr(), ItemIndex );
}

void __fastcall HCustomCharImage::InvDot( int x, int y )
  {
     if ( !CharDump.Sizeof() ||
          !FontBitmap )
       return;
     LPBYTE b = (LPBYTE)CharDump.Ptr();
     BYTE   v = 1<<(x%8);

     b += y*FontBitmap->CharWidthB + x/8;

     if ( !IS_FLAG( *b, v ) )
       SET_FLAG( *b, v );
      else
       CLR_FLAG( *b, v );

     FontBitmap->SetCharDump( (LPBYTE)CharDump.Ptr(), ItemIndex );
}

int __fastcall HCustomCharImage::X2N( int x ) { return x / (DotSize+1); }
int __fastcall HCustomCharImage::Y2N( int y ) { return y / (DotSize+1); }

void __fastcall HCustomCharImage::MouseMove( Classes::TShiftState Shift, int x, int y )
  {
     do{
       if ( !CharDump.Sizeof() ||
            !FontBitmap ||
            !FontBitmap->CharCount )
         break;

       x = X2N(x);
       y = Y2N(y);
       if ( x < 0 || y < 0 ||
            x >= FontBitmap->CharWidth ||
            y >= FontBitmap->CharHeight )
         break;

       if ( ox != x || oy != y ) {
         ox = x;
         oy = y;
         if ( OnDotMove )
           OnDotMove( this, Shift, x, y );
       }

       return;
     }while( 0 );

     TGraphicControl::MouseMove( Shift, x, y );
}

void __fastcall HCustomCharImage::MouseDown(TMouseButton Button, Classes::TShiftState Shift, int x, int y)
  {
     do{
       if ( !CharDump.Sizeof() ||
            !FontBitmap ||
            !FontBitmap->CharCount )
         break;

       x = X2N(x);
       y = Y2N(y);
       if ( x < 0 || y < 0 ||
            x >= FontBitmap->CharWidth ||
            y >= FontBitmap->CharHeight )
         break;

       ox = x;
       oy = y;
       if ( OnDotPress )
         OnDotPress( this, Button, Shift, x, y );

       return;
     }while( 0 );

     TGraphicControl::MouseDown( Button,Shift, x, y );
}

void __fastcall HCustomCharImage::Paint(void)
  {  TCanvas *dc = Canvas;
     MyRect   r( 0,0,Width,Height );

     TC_Fill( dc, r, Color );
     if ( !CharDump.Sizeof() ||
          !FontBitmap ||
          !FontBitmap->CharCount ||
          ItemIndex < 0 || ItemIndex >= FontBitmap->CharCount )
       return;

     LPBYTE b = (LPBYTE)CharDump.Ptr();
     int    cw = FontBitmap->CharWidth,
            w = FontBitmap->CharWidthB,
            h = FontBitmap->CharHeight;

     for( int n = 0; n < h; n++, b+=w )
       for( int i = 0; i < cw; i++ ) {
         TColor cl = IS_FLAG( b[ i/8 ], 1 << (i%8) ) ? FontBitmap->ColorPoint : FontBitmap->ColorSpace;

         r.x = (i+1)*1 + i*DotSize;
         r.y = (n+1)*1 + n*DotSize;
         r.x1 = r.x + DotSize;
         r.y1 = r.y + DotSize;

         TC_Fill( dc, r, cl );
       }
}

//---------------------------------------------------------------------------
//  HCharFontList
//---------------------------------------------------------------------------
__fastcall HCharFontList::HCharFontList( TComponent *Owner ) : HCustomCharFontList( Owner ) {}

__fastcall HCustomCharFontList::HCustomCharFontList( TComponent *Owner )
   : HCustomBkList(Owner)
  {
     FFontBitmap  = NULL;
     FShowNumbers = true;
     FMinHeight   = 19;
     FCharZoom    = 1;
     FCharSection = 0;
     FOptions << bkoVirtual;
}

DECL_PROP_SET( HCustomCharFontList, bool, ShowNumbers ) { HPropModify( FShowNumbers, val, &Change ); }
DECL_PROP_SET( HCustomCharFontList, int,  MinHeight )   { HPropModify( FMinHeight,   val, &Change ); }
DECL_PROP_SET( HCustomCharFontList, int,  CharZoom )    { HPropModify( FCharZoom,    val, &Change ); }
DECL_PROP_SET( HCustomCharFontList, int,  CharSection ) { HPropModify( FCharSection, val, &Change ); }

void __fastcall HCustomCharFontList::Notification( TComponent* p, TOperation op )
  {
     if ( p == FFontBitmap && op == opRemove )
       FontBitmap = NULL;

     HCustomBkList::Notification( p, op );
}

void __fastcall HCustomCharFontList::idItemChange( TObject *Sender, int idx ) { InvalidateItem( idx ); }
void __fastcall HCustomCharFontList::idChange( TObject *Sender )              { Change(); }

void __fastcall HCustomCharFontList::Change( void )
  {
     if ( FontBitmap && FontBitmap->CharCount ) {
       ItemHeight = Max( MinHeight, FontBitmap->CharHeight*CharZoom + 3 );
       ItemsCount = FontBitmap->CharCount;
     }
     Invalidate();
}

void __fastcall HCustomCharFontList::DoCorrectOptions( HBkListOptions& NewValue )
  {
     NewValue << bkoVirtual;
     NewValue >> bkoVariableHeight;
}

void __fastcall HCustomCharFontList::DoDrawItem( TCanvas *dc,int Index, const MyRect& Rect, const TOwnerDrawState& State)
  {
     do{
       if ( !FFontBitmap ) break;
       if ( Index < 0 || Index >= FontBitmap->CharCount ) break;

       FontBitmap->DrawChar( dc,
                             Rect.x+1, Rect.CenterY() - FontBitmap->CharHeight*CharZoom/2,
                             Index, CharZoom );

       if ( OnDrawItem && !OnDrawItem( this,dc,Index,Rect,State ) )
         break;

       return;
     }while(0);
     HCustomBkList::DoDrawItem( dc,Index,Rect,State );
}

void __fastcall HCustomCharFontList::DoDrawSection( TCanvas *dc,int Index,THeaderSection* p, const MyRect& Rect, const TOwnerDrawState& State )
  {
     do{
       if ( !FFontBitmap ) break;
       if ( Index < 0 || Index >= FontBitmap->CharCount ) break;
       if ( p->Index != CharSection ) break;

       FontBitmap->DrawChar( dc,
                             Rect.x+1, Rect.CenterY() - FontBitmap->CharHeight*CharZoom/2,
                             Index, CharZoom );

       {  HPenSave<TCanvas>  _ps( dc, HS_PEN_ALL );
          HFontSave<TCanvas> _fs( dc, HS_FONT_ALL );
          if ( OnDrawItemSection && !OnDrawItemSection( this,dc,Index,p,Rect,State ) )
             break;
       }

       return;
     }while(0);
     HCustomBkList::DoDrawSection( dc,Index,p,Rect,State );
}

DECL_PROP_SET( HCustomCharFontList, PHCustomFontBitmap, FontBitmap )
  {
     if ( FFontBitmap == val ) return;

     if ( FFontBitmap ) {
       FFontBitmap->Changes.Delete( idChange );
       FFontBitmap->ItemChanges.Delete( idItemChange );
     }

     FFontBitmap = val;

     if ( FFontBitmap ) {
       FFontBitmap->Changes.Add( idChange );
       FFontBitmap->ItemChanges.Add( idItemChange );
     }

     Change();
}

//---------------------------------------------------------------------------
//  HFontBitmap
//---------------------------------------------------------------------------
__fastcall HFontBitmap::HFontBitmap( TComponent *Owner ) : HCustomFontBitmap(Owner) {}

__fastcall HCustomFontBitmap::HCustomFontBitmap( TComponent *Owner )
   : TComponent(Owner)
  {
     Bitmap      = new HBitmap;

     FCharWidth  = 8;
     FCharHeight = 8;
     FColorSpace = clWhite;
     FColorPoint = clBlack;
}

__fastcall HCustomFontBitmap::~HCustomFontBitmap()
  {
     delete Bitmap;
}

DECL_PROP_GET( HCustomFontBitmap, int, CharWidthB ) { return CharWidth/8 + ((CharWidth%8) > 0); }

DECL_PROP_GET( HCustomFontBitmap, int, CharCount )
  {
     if ( !Bitmap->Width ||
          !Bitmap->Height )
       return 0;

 return Bitmap->Height / CharHeight;
}

void HCustomFontBitmap::DrawChar( TCanvas *dc, int x, int y, int idx, int sz )
  {
     if ( idx < 0 || idx >= CharCount )
       return;

     idx = idx*CharHeight;
     sz  = Max( 1, sz );

     int omode = SetStretchBltMode( dc->Handle, COLORONCOLOR );
     StretchBlt( dc->Handle,
                 x, y, CharWidth*sz, CharHeight*sz,
                 Bitmap->Canvas->Handle,
                 0, idx, CharWidth, CharHeight,
                 SRCCOPY );
     SetStretchBltMode( dc->Handle, omode );
}

bool HCustomFontBitmap::SetCharDump( LPCBYTE dump, int idx )
  {
     if ( idx < 0 || idx >= CharCount )
       return false;

     TCanvas *dc = Bitmap->Canvas;
     int      n,i, y;

     for( y = idx*CharHeight, n = 0; n < CharHeight; n++, y++, dump += CharWidthB )
       for( i = 0; i < CharWidth; i++ )
         if ( IS_FLAG( dump[ i/8 ], 1 << (i%8) ) )
           dc->Pixels[i][y] = ColorPoint;
          else
           dc->Pixels[i][y] = ColorSpace;

     DoChangeItem( idx );
     
 return true;
}

bool HCustomFontBitmap::GetCharDump( LPBYTE dump, int idx )
  {
     if ( idx < 0 || idx >= CharCount )
       return false;

     TCanvas *dc = Bitmap->Canvas;
     int      n,i;

     memset( dump, 0, CharWidthB*CharHeight );
     for( idx *= CharHeight, n = 0; n < CharHeight; n++, idx++, dump += CharWidthB )
       for( i = 0; i < CharWidth; i++ )
         if ( dc->Pixels[i][idx] == ColorPoint )
           SET_FLAG( dump[ i/8 ], 1 << (i%8) );
 return true;
}

void HCustomFontBitmap::DoChangeItem( int idx )
  {
     for( int n = 0; n < ItemChanges.Count(); n++ )
       ItemChanges[n]( this, idx );

     if ( OnItemChange )
       OnItemChange( this, idx );
}

void HCustomFontBitmap::DoChange( void )
  {
     for( int n = 0; n < Changes.Count(); n++ )
       Changes[n]( this );

     if ( OnChange )
       OnChange( this );
}

bool HCustomFontBitmap::LoadCharsDump( LPBYTE dump, int count, int charsz, HFontDecodeEvent cb )
  {  int csz = CharWidthB * CharHeight;
     if ( csz != charsz &&
          !cb ) {
       FIO_SETERRORN( ERROR_INVALID_PARAMETER );
       return false;
     }

     HDataPtr dd;
     if ( !dd.Resize( CharWidthB*csz ) )
       return false;

     __try{
       Bitmap->Width  = CharWidth;
       Bitmap->Height = CharHeight * count;
     }catch(...){
       Bitmap->SetEmpty();
       return false;
     }
     TC_Fill( Bitmap->Canvas, 0, 0, Bitmap->Width, Bitmap->Height, ColorSpace );

     for( int n = 0; n < count; dump+=charsz, n++ ) {
       memset( dd.Ptr(), 0, csz );
       if ( cb )
         cb( this, (LPBYTE)dd.Ptr(), dump );

       SetCharDump( (LPBYTE)dd.Ptr(), n );
     }

 return true;
}

bool HCustomFontBitmap::LoadCharsFile( CONSTSTR fnm, int count, int charsz, long off, HFontDecodeEvent cb )
  {  bool rc = DoLoadCharsFile( fnm, count, charsz, off, cb );

     if ( !rc )
       Bitmap->SetEmpty();

     DoChange();

 return rc;
}

bool HCustomFontBitmap::DoLoadCharsFile( CONSTSTR fnm, int count, int charsz, long off, HFontDecodeEvent cb )
  {
     int csz = CharWidthB * CharHeight;
     if ( csz != charsz &&
          !cb ) {
       FIO_SETERRORN( ERROR_INVALID_PARAMETER );
       return false;
     }

     FIO_Save f( FIO_OPEN(fnm,O_RDONLY) );
     if ( f == -1 )
       return false;

     if ( off )
       if ( FIO_SEEK( f, off, seekBEGIN ) != off )
         return false;

     HDataPtr sd, dd;
     if ( !sd.Resize( charsz ) ||
          !dd.Resize( CharWidthB*csz ) )
       return false;

     __try{
       Bitmap->Width  = CharWidth;
       Bitmap->Height = CharHeight * count;
     }catch(...){
       Bitmap->SetEmpty();
       return false;
     }
     TC_Fill( Bitmap->Canvas, 0, 0, Bitmap->Width, Bitmap->Height, ColorSpace );

     for( int n = 0; n < count; n++ ) {
       if ( FIO_READ( f, sd.Ptr(), charsz ) != charsz )
         return false;

       memset( dd.Ptr(), 0, csz );
       if ( cb )
         cb( this, (LPBYTE)dd.Ptr(), (LPBYTE)sd.Ptr() );

       SetCharDump( (LPBYTE)dd.Ptr(), n );
     }

     f.Close();

 return true;
}

bool HCustomFontBitmap::SaveCharsFile( CONSTSTR fnm, int count, int charsz, long off, HFontDecodeEvent cb )
  {
     int csz = CharWidthB * CharHeight;
     if ( csz != charsz &&
          !cb ) {
       FIO_SETERRORN( ERROR_INVALID_PARAMETER );
       return false;
     }

     FIO_Save f( FIO_OPEN(fnm,O_WRONLY) );
     if ( f == -1 ) {
       if ( off != 0 ||
            (f=FIO_CREAT( fnm,0 )) == -1 )
         return false;
     }

     if ( off )
       if ( FIO_SEEK( f, off, seekBEGIN ) != off )
         return false;

     HDataPtr sd, dd;
     if ( !sd.Resize( charsz ) ||
          !dd.Resize( CharWidthB*csz ) )
       return false;

     for( int n = 0; n < count; n++ ) {
       GetCharDump( (LPBYTE)dd.Ptr(), n );

       memset( sd.Ptr(), 0, charsz );
       if ( cb )
         cb( this, (LPBYTE)sd.Ptr(), (LPBYTE)dd.Ptr() );

       if ( FIO_WRITE( f, sd.Ptr(), charsz ) != charsz )
         return false;
     }

 return true;
}

//---------------------------------------------------------------------------
//  TFontEditForm
//---------------------------------------------------------------------------
__fastcall TFontEditForm::TFontEditForm(TComponent* Owner)
    : TForm(Owner)
  {
     open->InitialDir = GetStartupDir(NULL);

     font = new HFontBitmap( this );
       font->OnChange    = idChange;

     list = new HCharFontList( panList );
       list->FontBitmap = font;
       list->Align      = alClient;
       list->Options >> bkoTrackItem >> bkoShowBorder;
       list->OnDrawItem = idDrawItem;
       list->OnClick    = idListClick;
     panList->InsertControl( list );

     image = new HCharImage( panDraw );
       image->FontBitmap = font;
       image->Align      = alClient;
       image->OnDotMove  = idMouseMove;
       image->OnDotPress = idMouseDown;
     panDraw->InsertControl( image );

     ActiveControl = list;
}
//---------------------------------------------------------------------------
void __fastcall TFontEditForm::FormCreate(TObject *Sender)
  {
     for( int n = 0; n < ARRAY_SIZE(KnownChars); n++ )
       edtOff->Items->Add( KnownChars[n].Name );
     edtOff->ItemIndex = 0;
     edtOffClick(NULL);

     btnZoomClick( NULL, btNext );
     btnDotSizeClick( NULL, btNext );
     edtCharsChange(NULL);
}
//---------------------------------------------------------------------------
void __fastcall TFontEditForm::idDump2Char( TObject *Sender, LPBYTE dst, LPCBYTE src )
  {  int w  = font->CharWidthB,
         nl = btnNLen->Position,
         np = btnNPair->Position;

     int off;
     for( int i = 0; i < nl; i++ )
       for( int n = 0; n < np; src++, n++ )
         for( int b = 0; b < 8; b++ ) {
           off = (i*8 + b)*w + n/8;
           if ( IS_FLAG( *src, 1<<b ) )
             SET_FLAG( dst[ off ], 1 << (n%8) );
         }
}
void __fastcall TFontEditForm::idChar2Dump( TObject *Sender, LPBYTE dst, LPCBYTE src )
  {  int w  = font->CharWidthB,
         np = btnNPair->Position,
         ch = font->CharHeight,
         cw = font->CharWidth;

     for( int y = 0; y < ch; src += w, y++ )
       for( int x = 0; x < cw; x++ ) {
         int bit = x % 8;
         if ( !IS_FLAG( src[ x / 8 ], 1 << bit ) )
           continue;

         SET_FLAG( dst[ (y/8) * np + bit ], 1 << (y%8) );
       }
}
void __fastcall TFontEditForm::idListClick( TObject *Sender )
  {
    image->ItemIndex = list->ItemIndex;
}
void __fastcall TFontEditForm::idChange( TObject *Sender )
  {
      list->Invalidate();
}
bool __fastcall TFontEditForm::idDrawItem(TObject *Sender, TCanvas *dc,
      int Index, const MyRect &Rect, const TOwnerDrawState &State)
  {
     TC_TextOut( dc, Rect.Inflated(-2,-1),
                 Message( "+%04X %3d (%02X)",
                          btnNPair->Position*btnNLen->Position*Index,
                          Index, Index ),
                 DT_SINGLELINE|DT_RIGHT|DT_VCENTER );

 return true;
}
void __fastcall TFontEditForm::idMouseMove(TObject *Sender, Classes::TShiftState Shift, int x, int y)
  {
     if ( Shift.Contains(ssLeft) )
       image->InvDot( x,y );
}
void __fastcall TFontEditForm::idMouseDown(TObject *Sender, TMouseButton Button, Classes::TShiftState Shift, int x, int y)
  {
     if ( Button == mbLeft )
       image->InvDot( x,y );
}
//---------------------------------------------------------------------------
void __fastcall TFontEditForm::btnOpenClick(TObject *Sender)
{
     if ( !open->Execute() ) return;
     edtFile->Text = open->FileName;
}
//---------------------------------------------------------------------------
void __fastcall TFontEditForm::edtOffClick(TObject *Sender)
  {  int n = edtOff->ItemIndex;
     if ( n >= 0 && n < ARRAY_SIZE(KnownChars) ) {
       edtOff->Text = Message( "0x%08X", KnownChars[n].off );
       btnNChars->Position = KnownChars[n].nChars;
       btnNLen->Position = KnownChars[n].nLen;
       btnNPair->Position = KnownChars[n].nPair;
     }
}
//---------------------------------------------------------------------------
void __fastcall TFontEditForm::btnImportClick(TObject *Sender)
  {
    if ( font->CharCount &&
         !AskYesNo( Handle, NULL, "Font contains data.\nImport new data anyway?" ) )
      return;

    font->CharWidth  = btnNPair->Position;
    font->CharHeight = btnNLen->Position * 8;

    if ( !font->LoadCharsFile( edtFile->Text.c_str(),
                               btnNChars->Position,
                               btnNLen->Position*btnNPair->Position,
                               Str2DigitDetect( StrGetCol(edtOff->Text.c_str(),1," "),10,0),
                               idDump2Char ) )
      AskMessage( Handle, NULL,
                  "Error loading data.\nFile: %s\nError: %s",
                  edtFile->Text.c_str(), FIO_ERROR );
}
//---------------------------------------------------------------------------
void __fastcall TFontEditForm::btnZoomClick(TObject *Sender,TUDBtnType Button)
  {
     list->CharZoom = btnZoom->Position;
}
//---------------------------------------------------------------------------
void __fastcall TFontEditForm::btnExportClick(TObject *Sender)
{
    if ( !font->CharCount )
      return;

    AnsiString fnm = edtFile->Text;
    long       off = Str2DigitDetect( StrGetCol(edtOff->Text.c_str(),1," "), 10, 0 );

    if ( !AskYesNo( Handle, NULL,
                    "You shure to set dump of %d bytes [+%08X]\ninto file \"%s\"?",
                    btnNLen->Position*btnNPair->Position*btnNChars->Position,
                    off,
                    fnm.c_str() ) )
      return;

    if ( !font->SaveCharsFile( fnm.c_str(),
                               btnNChars->Position,
                               btnNLen->Position*btnNPair->Position,
                               off,
                               idChar2Dump ) )
      AskMessage( Handle, NULL,
                  "Error storing data.\nFile: %s\nError: %s",
                  fnm.c_str(), FIO_ERROR );
     else
      AskMessage( Handle, NULL, "Font data has been successfully exported" );
}
//---------------------------------------------------------------------------
void __fastcall TFontEditForm::btnDotSizeClick(TObject *Sender,TUDBtnType Button)
  {
     image->DotSize = btnDotSize->Position;
}
//---------------------------------------------------------------------------
void __fastcall TFontEditForm::edtCharsChange(TObject *Sender)
  {  MyString _t( edtChars->Text );
     CONSTSTR t = _t.c_str(),
              s = ToOEM(t);
     char     buff[ 100 ],
             *m = buff;

     txtChars->Lines->Clear();
     for( ; *s; t++, s++ ) {
       m += sprintf( m, " %02X-\'%c\'", (BYTE)(*s), (BYTE)(*t) );

       if ( (m-buff) > 60 ) {
         *m = 0;
         txtChars->Lines->Add( buff );
         m = buff;
       }
     }

     if ( m > buff ) {
       *m = 0;
       txtChars->Lines->Add( buff );
     }
}
//---------------------------------------------------------------------------
